package cn.edu.sjtu.se.dslab.controller;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import cn.edu.sjtu.se.dslab.auth.CommonVariableModel;
import cn.edu.sjtu.se.dslab.auth.User;
import cn.edu.sjtu.se.dslab.component.data.DomainEntity;
import cn.edu.sjtu.se.dslab.component.design.generate.DesignPatternCodeUtil;
import cn.edu.sjtu.se.dslab.component.method.MethodComponent;
import cn.edu.sjtu.se.dslab.project.EntityZone;
import cn.edu.sjtu.se.dslab.project.EntityZoneCategory;
import cn.edu.sjtu.se.dslab.project.PGroup;
import cn.edu.sjtu.se.dslab.project.Project;
import cn.edu.sjtu.se.dslab.project.UserProject;
import cn.edu.sjtu.se.dslab.rhapsody.entity.Agent;
import cn.edu.sjtu.se.dslab.rhapsody.service.RhapsodyFileService;
import cn.edu.sjtu.se.dslab.service.IAuthService;
import cn.edu.sjtu.se.dslab.service.IDomainEntityService;
import cn.edu.sjtu.se.dslab.service.IEntityZoneCategoryService;
import cn.edu.sjtu.se.dslab.service.IEntityZoneService;
import cn.edu.sjtu.se.dslab.service.IMethodComponentService;
import cn.edu.sjtu.se.dslab.service.IPGroupService;
import cn.edu.sjtu.se.dslab.service.IProjectService;
import cn.edu.sjtu.se.dslab.service.IUserProjectService;
import cn.edu.sjtu.se.dslab.service.IUserService;

@Controller
@RequestMapping(value = "/project")
public class ProjectController {
	private static final Logger logger = Logger.getLogger(ProjectController.class);

	@Resource(name = "projectService")
	IProjectService projectService;

	@Resource(name = "pgroupService")
	IPGroupService pgroupService;

	@Resource(name = "userService")
	IUserService userService;
	
	@Resource(name="userProjectService")
	IUserProjectService userProjectService;
	
	@Resource(name="entityZoneService")
	IEntityZoneService entityZoneService;
	
	@Resource(name="domainEntityService")
	IDomainEntityService domainEntityService;

	@Resource(name = "authService")
	IAuthService authService;
	
	@Resource(name="rhapsodyFileService")
	RhapsodyFileService rhapsodyFileService;
	
	@Resource(name = "entityZoneCategoryService")
	IEntityZoneCategoryService entityZoneCategoryService;
	
	@Resource(name = "methodComponentService")
	IMethodComponentService methodComponentService;
	
	
	@RequestMapping(value = "/add", method = RequestMethod.POST)
	public String addProject(Project project, Long groupID) {
		Subject user1 = SecurityUtils.getSubject();
		if (user1 != null) {
			CommonVariableModel model = (CommonVariableModel) user1
					.getPrincipals().getPrimaryPrincipal();
			project.setOwner(model.getUser());
			User user = model.getUser();

			PGroup pgroup = pgroupService.getPGroupById(groupID);

			project.setPgroup(pgroup);

			// create the project folder under the user's folder
			StringBuffer folderPath = new StringBuffer("userdata/");
			folderPath.append(user.getUsername()).append("/")
					.append("project/").append(project.getName()).append("/");
			project.setFolderPath(folderPath.toString());
			projectService.addProject(project);
		} else {
			System.out.println("no user logined");
		}

		return "redirect:/project/list";
	}

	@RequestMapping(value = "/list", method = RequestMethod.GET)
	public ModelAndView getProjectList() {
		ModelAndView mav = new ModelAndView();
		mav.setViewName("manageProject");
		User user = getUser();
		if (user != null){
			//List<Project> projects = userProjectService.getProjectListByUser(user);
			//mav.addObject("projects", projects.iterator());
			List<UserProject> userProjects = userProjectService.getListByUser(user);
			mav.addObject("userProjects", userProjects.iterator());
		}
		return mav;
	}
	
	@RequestMapping(value = "/{projectId}/entityZone/edit", method = RequestMethod.GET)
	public ModelAndView getEntityZoneByProject(@PathVariable(value = "projectId")long projectId){
		ModelAndView mav = new ModelAndView();
		List<EntityZoneCategory> entityZoneCategorys = entityZoneCategoryService.getEntityZoneCategoryByProject(projectId);
		mav.addObject("entityZoneCategorys", entityZoneCategorys);
		
		List<EntityZone> entityZones = entityZoneService.getEntityZoneByProject(projectId);
		mav.addObject("entityZones", entityZones);
		for (EntityZone entityZone : entityZones){
			DomainEntity entity = domainEntityService.getDomainEntityByUri(entityZone.getEntityUri());
			if (entity!=null){
				entityZone.setEntityUri(entity.getName());
			}
		}
		List<Project> projects = projectService.getProjectList();
		mav.addObject("projects", projects.iterator());
		Project project = projectService.getProjectById(projectId);
		mav.addObject("project", project);
		List<DomainEntity> domainEntities = domainEntityService
				.getAllDomainEntity();
		mav.addObject("domainEntitys", domainEntities);
		mav.setViewName("editEntityZone");
		return mav;
	}
	
	@RequestMapping(value = "/menu", method = RequestMethod.GET)
	@ResponseBody
	public Project getProjectInfo() {
		Subject user = SecurityUtils.getSubject();
		if (user != null) {
			CommonVariableModel model = (CommonVariableModel) user
					.getPrincipals().getPrimaryPrincipal();
			long projectId = model.getProjectId();
			ModelAndView mav = new ModelAndView();
			mav.setViewName("projectMenu");
			if (0 == projectId){ 
				logger.info("No selected Project");
				return null;
			}
			Project project = projectService.getProjectById(projectId);
			//project.setModel(null);
			if (project.getModel() != null) {
				project.getModel().setOwner(null);
				project.getModel().setProject(null);
				project.getModel().setLogers(null);
			}
			project.setDesignPatternComponents(null);
			project.setOwner(null);
			project.setPgroup(null);
			mav.addObject("project", project);
			return project;
		} else {
			System.out.println("no login user");
			return null;
		}
	}
	
	@RequestMapping(value = "/list/{projectId}", method = RequestMethod.GET)
	public ModelAndView getProjectInfo(@PathVariable(value = "projectId") Long projectId) {
		Subject user = SecurityUtils.getSubject();
		if (user != null) {
			CommonVariableModel model = (CommonVariableModel) user
					.getPrincipals().getPrimaryPrincipal();
			model.setProjectId(projectId);
			System.out.println("set project id:" + projectId);
		} else {
			System.out.println("no login user");
		}
		ModelAndView mav = new ModelAndView();
		mav.setViewName("home");
		//List<Project> projects = projectService.getProjectList();
//		mav.addObject("projects", projects);
//		if (projectId != null) {
//			Project project = projectService.getProjectById(projectId);
//			return project;
//		}
		return mav;
	}
	
	@RequestMapping(value="/{projectId}/delete", method= RequestMethod.DELETE)
	@ResponseBody
	public Map<String,String> deleteProject(@PathVariable(value="projectId") Long projectId){
		logger.info("Delete Project " + projectId);
		Map<String, String> responseMap = new HashMap<String, String>();
		try {
			boolean result = projectService.deleteProject(projectId);
			if (result) {
				responseMap.put("result", Boolean.TRUE.toString());
			} else {
				responseMap.put("result", Boolean.FALSE.toString());
			}
		} catch (Exception ex) {
			responseMap.put("result", Boolean.FALSE.toString());
		}
		return responseMap;
	}
	

//	@RequestMapping(value = "/list/{projectId}", method = RequestMethod.GET)
//	@ResponseBody
//	public Project getProjectInfo(@PathVariable(value = "projectId") Long projectId) {
//		Subject user = SecurityUtils.getSubject();
//		if (user != null) {
//			CommonVariableModel model = (CommonVariableModel) user
//					.getPrincipals().getPrimaryPrincipal();
//			model.setProjectId(projectId);
//			System.out.println("set project id:" + projectId);
//		} else {
//			System.out.println("no login user");
//		}
//
//		ModelAndView mav = new ModelAndView();
//		mav.setViewName("projectMenu");
//		List<Project> projects = projectService.getProjectList();
//		mav.addObject("projects", projects);
//		if (projectId != null) {
//			Project project = projectService.getProjectById(projectId);
//			project.setModel(null);
//			project.setDesignPatternComponents(null);
//			project.setOwner(null);
//			project.setPgroup(null);
//			return project;
//		}
//		return null;
//	}
	
	@RequestMapping(value = "/list/{projectId}/user", method = RequestMethod.GET)
	public ModelAndView getUserOfProject(@PathVariable(value = "projectId") Long projectId) {
		ModelAndView mav = new ModelAndView();
		mav.setViewName("addUserProjects");
		Project project = projectService.getProjectById(projectId);
		if(null == project) return null;
		PGroup pGroup = project.getPgroup();
		if(null == pGroup) return null;
		
		List<UserProject> userProjects = userProjectService.getListByProject(project);
		mav.addObject("userProjects", userProjects);
		mav.addObject("project", project);
		mav.addObject("pgroup", pGroup);
		Set<User> userset = new HashSet<User>();
		for (UserProject userProject : userProjects){
			userset.add(userProject.getUser());
		}
		Set<User> users = pGroup.getUsers();
		users.removeAll(userset);  //去掉以及添加的用户
		mav.addObject("users", users);
		return mav;
	}

	@RequestMapping(value = "/addProjects", method = RequestMethod.GET)
	public ModelAndView addProject() {
		ModelAndView mav = new ModelAndView();
		mav.setViewName("addProjects");
		//List<PGroup> pgroups = pgroupService.getPGroupList();
		User user = getUser();
		if (user != null) {
			user = authService.getUserById(user.getId());
			Set<PGroup> pgroups = user.getpGroups();
			mav.addObject("pgroups", pgroups.iterator());
		}else {
			mav.setViewName("login");
		}
		return mav;
	}

	@RequestMapping(value = "/list/{username}/json", method = RequestMethod.GET)
	@ResponseBody
	public List<Project> getProjectJsonList(@PathVariable(value = "username") String username) {
		User user = userService.getUserByUsername(username);
		List<Project> projects = null;
		if (null != user) {
			projects = userProjectService.getProjectListByUser(user);
			logger.info(projects.size());
			for (Project p : projects) {
				p.setModel(null);
				p.setDesignPatternComponents(null);
				p.setOwner(null);
				p.setPgroup(null);
				p.setCreateTime(null);
				logger.info(p.getName());
			}
		}
		return projects;
	}
	
	@RequestMapping(value = "/{projectId}/generateCode", method = RequestMethod.GET)
	public void generateCode(@PathVariable(value = "projectId") long projectId,
			HttpServletResponse response) throws IOException {

		DesignPatternCodeUtil codeUtil = new DesignPatternCodeUtil(projectId);
		String codeFilePath = codeUtil.generateDesignPatternCode();
		

		File zipFile = new File(codeFilePath);
		InputStream is = new FileInputStream(zipFile);
		response.setContentType("application/octet-stream");
		response.setContentLength((int) zipFile.length());
		String headerKey = "Content-Disposition";
		String headerValue = String.format("attachment;filename=\"%s\"",
				zipFile.getName());
		response.setHeader(headerKey, headerValue);
		IOUtils.copy(is, response.getOutputStream());
		response.flushBuffer();
	}
	
	@RequestMapping(value = "/{projectId}/importRhapsody", method = RequestMethod.GET)
	public ModelAndView importRhapsody(@PathVariable(value = "projectId") Long projectId) {
		ModelAndView mav = new ModelAndView();
		Project project = projectService.getProjectById(projectId);
		
		mav.addObject("displayZones", rhapsodyFileService.getDisplayZoneAndDomainEntityTuple(projectId));
		mav.addObject("entityZones", rhapsodyFileService.getEntityZoneAndDomainEntityTuple(projectId));
		mav.addObject("busAgents", rhapsodyFileService.readXmiBusAgents(projectId));
		mav.addObject("controlResponses", rhapsodyFileService.readXmiControlResponses(projectId));
		mav.addObject("busZones", rhapsodyFileService.readXmiBusZones(projectId));
		
		mav.addObject("entityZoneCategorys", entityZoneCategoryService.getEntityZoneCategoryByProject(projectId));
		
		mav.addObject("project", project);
		mav.setViewName("importRhapsody");
		return mav;
	}
	
	@RequestMapping(value = "/{projectId}/downLoadCode", method = RequestMethod.GET)
	public ModelAndView downLoadCodePage(@PathVariable(value = "projectId") Long projectId) {
		ModelAndView mav = new ModelAndView();
		Project project = projectService.getProjectById(projectId);
		List<MethodComponent> methodComponents  = methodComponentService.getAllMethodComponents();
		
		mav.addObject("methodComponents", methodComponents);
		mav.addObject("project", project);
		mav.setViewName("downLoadCode");
		return mav;
	}
	
	@RequestMapping(value = "/{projectId}/realMachineCode", method = RequestMethod.GET)
	public void realMachineCode(@PathVariable(value = "projectId") long projectId,
			HttpServletResponse response) throws IOException {

		DesignPatternCodeUtil codeUtil = new DesignPatternCodeUtil(projectId);
		String codeFilePath = codeUtil.generateRealMachineCode(); //真机代码
		File zipFile = new File(codeFilePath);
		InputStream is = new FileInputStream(zipFile);
		response.setContentType("application/octet-stream");
		response.setContentLength((int) zipFile.length());
		String headerKey = "Content-Disposition";
		String headerValue = String.format("attachment;filename=\"%s\"",
				zipFile.getName());
		response.setHeader(headerKey, headerValue);
		IOUtils.copy(is, response.getOutputStream());
		response.flushBuffer();
	}

	private User getUser() {
		Subject subject = SecurityUtils.getSubject();
		if (subject != null && subject.getPrincipals() != null) {
			CommonVariableModel model = (CommonVariableModel) subject
					.getPrincipals().getPrimaryPrincipal();
			return model.getUser();
		}
		return null;
	}

}
